package com.atguigu.gulimall.product.web;

import com.alibaba.fastjson.JSON;
import com.atguigu.gulimall.product.VO.Catelog2Vo;
import com.atguigu.gulimall.product.entity.CategoryEntity;
import com.atguigu.gulimall.product.service.CategoryService;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Controller
public class IndexController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedissonClient redisson;

    @GetMapping({"/", "/index.html"})
    public String indexPage(Model model) {
        // TODO: 2021/9/13 ，1查出所有分类
        List<CategoryEntity> categoryEntities = categoryService.getLevel1Categorys();

        model.addAttribute("categorys", categoryEntities);

        return "index";
    }

    // index/catalog.json
    @ResponseBody
    @GetMapping("/index/catalog.json")
    public Map<String, List<Catelog2Vo>> getCatelogJson() {
        Map<String, List<Catelog2Vo>> map = categoryService.getCatelogJson();

        return map;
    }

    @ResponseBody
    @GetMapping("product/hello")
    public String hello() {
        // 获取锁
        RLock lock = redisson.getLock("my-lock");
        // 加锁
        // 有看门狗，可以自动续期。
        // 当前线程出现错误，不能释放锁的时候，锁会过期自动解锁
        lock.lock(10, TimeUnit.SECONDS);

        try {
            System.out.println("加锁成功。。。执行业务代码。。。" + Thread.currentThread().getId());
            Thread.sleep(20000);
        } catch (Exception e) {
        } finally {
            // 解锁
            lock.unlock();
        }

        System.out.println("释放锁。。。" + Thread.currentThread().getId());
        return "hello";
    }

    /**
     * 写锁是一个排他锁，读锁是共享锁，其他线程都能共享
     * 在写锁的时候其他的读写都要等写锁释放后才能执行
     * <p>
     * 写 - 写：阻塞
     * 写 - 读：阻塞
     * 读 - 写：阻塞
     * 读 - 读：共享
     */
    @ResponseBody
    @GetMapping("/write")
    public String write() {
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        // 获取写锁
        RLock rLock = lock.writeLock();

        // 加锁
        rLock.lock();
        String uuid = UUID.randomUUID().toString();
        try {
            System.out.println("写锁已经加上。。。" + Thread.currentThread().getId());
            // 业务代码
            Thread.sleep(20000);
            redisTemplate.opsForValue().set("writeValue", uuid);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关锁
            rLock.unlock();
            System.out.println("写锁已经关闭。。。" + Thread.currentThread().getId());
        }

        return uuid;
    }

    @ResponseBody
    @GetMapping("/read")
    public String read() {
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        // 获取读锁
        RLock rLock = lock.readLock();

        // 加锁
        rLock.lock();
        String uuid = "";
        try {
            System.out.println("读锁已经加上。。。" + Thread.currentThread().getId());
            // 业务代码
            Thread.sleep(20000);
            uuid = redisTemplate.opsForValue().get("writeValue");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关锁
            rLock.unlock();
            System.out.println("读锁已经关闭。。。" + Thread.currentThread().getId());
        }

        return uuid;
    }

    /**
     * 当五个班都走完可以锁门
     */
    @ResponseBody
    @GetMapping("/lockDore")
    public String lockDore() throws InterruptedException {
        // 获取闭锁
        RCountDownLatch door = redisson.getCountDownLatch("door");
        // 设置数量
        door.trySetCount(5L);
        // 加锁，等到数量减为0就可以往后执行
        door.await();

        return "锁门了";
    }

    @ResponseBody
    @GetMapping("/gogogo/{id}")
    public String gogogo(@PathVariable("id") Integer id) {
        // 获取闭锁
        RCountDownLatch door = redisson.getCountDownLatch("door");
        // 闭锁数量减一
        door.countDown();

        return id == 5 ? "5个班都走完了。。。" : id + " 班关门了。。。";
    }

    /**
     * 先给redis中设置一个park value=3
     * 代表停车位，超过三个就不能挺了
     */
    @ResponseBody
    @GetMapping("/park")
    public String park() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("park");

        // 1 消耗一个，如果剩下的值为0，就等待。
//        park.acquire();
        // 2 消耗一个，不管有没有剩下都继续执行，获取成功返回true，获取失败返回false
        boolean tryAcquire = park.tryAcquire();

        if (tryAcquire) {
            // 停车成功，业务代码
        }

        return "park -> " + tryAcquire;
    }

    @ResponseBody
    @GetMapping("/go")
    public String go() {
        RSemaphore park = redisson.getSemaphore("park");

        // 释放一个车位
        park.release();

        return "go";
    }
}